/*
 * Copyright 2020 Echedey López Romero.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.nio.charset.Charset;
import java.util.Random;

/**
 * Software que se usará en los equipos.
 *
 * @author Echedey López Romero
 */
public class Software implements Comparable<Software> {

	private String compania;
	private String nombre;
	private double version;
	private String licencia;
	private TipoSoftware tipo;

	/**
	 * Inicializa la información del software con los parámetros introducidos a
	 * excepción de la licencia que es generada por generarLicencia si se indica
	 * por parámetro que tiene.
	 *
	 * @param compania nombre de la compañia
	 * @param nombre nombre del software
	 * @param version version del software
	 * @param tieneLicencia si tiene o no licencia
	 * @param tipo tipo de software
	 */
	public Software(String compania, String nombre, double version, boolean tieneLicencia, TipoSoftware tipo) {

		if (compania == null) {
			throw new NullPointerException("No se ha introducido la compañía.");
		} else if (nombre == null) {
			throw new NullPointerException("No se ha introducido el nombre.");
		} else if (version <= 0) {
			throw new IllegalArgumentException("Se ha introducido un número de versión incorrecto.");
		} else if (tipo == null) {
			throw new NullPointerException("No se ha introducido el tipo de software.");
		} else {
			this.compania = compania;
			this.nombre = nombre;
			this.version = version;
			if (tieneLicencia) {
				licencia = generarLicencia();
			} else {
				licencia = null;
			}
			this.tipo = tipo;
		}
	}

	/**
	 * Getter para compania.
	 *
	 * @return compania
	 */
	public String getCompania() {
		return compania;
	}

	/**
	 * Getter para nombre.
	 *
	 * @return nombre
	 */
	public String getNombre() {
		return nombre;
	}

	/**
	 * Getter para la version.
	 *
	 * @return version
	 */
	public double getVersion() {
		return version;
	}

	/**
	 * Getter para la licencia.
	 *
	 * @return licencia o null si no tiene
	 */
	public String getLicencia() {
		return licencia;
	}

	/**
	 * Getter para el tipo de software.
	 *
	 * @return tipo de TipoSoftware
	 */
	public TipoSoftware getTipo() {
		return tipo;
	}

	/**
	 * Incrementa el numero de la version de forma aleatoria en base al
	 * resultado de estaObsoleto.
	 *
	 * @return true si se pudo efectuar y false si no
	 */
	public boolean actualizarVersion() {
		if (estaObsoleto()) {
			double incrementoVersion = Math.random() * 10 + 1;

			if (incrementoVersion >= getVersion()) {
				return false;
			} else {
				version += incrementoVersion;
				return true;
			}
		} else {
			return true;
		}
	}

	/**
	 * Determina si el software está obsoleto de forma aleatoria. Un 50% de
	 * probabilidad.
	 *
	 * @return true si lo está y false si no lo está
	 */
	private boolean estaObsoleto() {
		return ((int) (Math.random() * 2 + 1) == 2);
	}

	/**
	 * Renueva la licencia mediante generarLicencia en base al resultado de
	 * estaCaducado.
	 *
	 * @return true si se pudo efectuar y false si no
	 */
	public boolean renovarLicencia() {
		if (estaCaducado()) {
			String nuevaLicencia = generarLicencia();

			if (nuevaLicencia.compareTo(getLicencia()) == 0) {
				return false;
			} else {
				licencia = nuevaLicencia;
				return true;
			}
		} else {
			return true;
		}
	}

	/**
	 * Genera una nueva licencia de forma aleatoria.
	 *
	 * @return licencia
	 */
	private String generarLicencia() {
		byte[] codigoBytes = new byte[10];
		new Random().nextBytes(codigoBytes);
		String otralicencia = new String(codigoBytes, Charset.forName("US-ASCII"));

		return otralicencia;
	}

	/**
	 * Determina si la licencia está caducada de forma aleatoria. Un 20% de
	 * probabilidad.
	 *
	 * @return true si lo está y false si no lo está
	 */
	private boolean estaCaducado() {
		return ((int) (Math.random() * 5 + 1) == 1);
	}

	/**
	 * Genera un resumen de la información del software bien estructurado.
	 *
	 * @return resumen del software
	 */
	@Override
	public String toString() {
		String informacion = "Compañía: " + getCompania() + "\n"
				+ "Nombre: " + getNombre() + "\n"
				+ "Versión: " + getVersion() + "\n";

		if (getLicencia() == null) {
			informacion += "Licencia: No tiene \n";
		} else {
			informacion += "Licencia: " + getLicencia() + "\n";
		}

		if (getTipo() == TipoSoftware.SISTEMAOPERATIVO) {
			informacion += "Tipo: Aplicación \n\n";
		} else {
			informacion += "Tipo: Sistema Operativo \n\n";
		}

		return informacion;
	}

	/**
	 * Compara software en base al tipo, la compañía y el nombre mediante el
	 * compareToIgnoreCase para cadenas.
	 *
	 * @param otroSoftware software a comparar
	 * @return comparación de cadenas
	 */
	@Override
	public int compareTo(Software otroSoftware) {
		String infoSoftware = getTipo()
				+ getCompania()
				+ getNombre();
		String infoOtroSoftware = otroSoftware.getTipo()
				+ otroSoftware.getCompania()
				+ otroSoftware.getNombre();

		return infoSoftware.compareToIgnoreCase(infoOtroSoftware);
	}

	/**
	 * Indica si otro software es el mismo en base a su nombre y su compañia.
	 *
	 * @param otroObjeto objeto de Object a comparar
	 * @return true si es idéntico y false si no
	 */
	@Override
	public boolean equals(Object otroObjeto) {
		if (otroObjeto instanceof Software) {
			Software otroSoftware = (Software) otroObjeto;

			String infoSoftware = getCompania()
					+ getNombre();
			String infoOtroSoftware = otroSoftware.getCompania()
					+ otroSoftware.getNombre();

			return (infoSoftware.compareToIgnoreCase(infoOtroSoftware) == 0);
		} else {
			return false;
		}
	}

}
